﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.ComponentModel;
using Tsanie.Mp3Tag;
using Tsanie.ShellExtension.Util;

namespace Tsanie.ShellExtension.PropertySheet.UI {
    public class PictureBoxEx : Panel {
        public event EventHandler ImageChanged;
        private PictureBox picture;
        private int offsetX, offsetY;
        private Image image;
        private byte[] imageData;

        public Image Image { get { return image; } }
        [DefaultValue(null)]
        public byte[] ImageData {
            get { return imageData; }
            set {
                try {
                    imageData = value;
                    image = TagUtil.GetImage(imageData);
                    SetImage(image);
                } catch (Exception e) {
                    Common.OutputDebugString("set_ImageData(byte[]):: Get image failed. {0} - {1}", e.GetType().FullName, e.Message);
                }
            }
        }

        public PictureBoxEx() {
            SetStyle(ControlStyles.AllPaintingInWmPaint
                   | ControlStyles.OptimizedDoubleBuffer
                   | ControlStyles.UserPaint
                     , true);
            this.AutoScroll = true;
            picture = new PictureBox();
            picture.MouseClick += new MouseEventHandler(picture_MouseClick);
            picture.MouseDown += new MouseEventHandler(picture_MouseDown);
            picture.MouseMove += new MouseEventHandler(picture_MouseMove);
            picture.SizeMode = PictureBoxSizeMode.StretchImage;
            picture.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.Controls.Add(picture);
            this.MouseClick += new MouseEventHandler(picture_MouseClick);
            this.AllowDrop = true;
        }

        private void SetImage(Image img) {
            image = img;
            picture.Image = image;
            if (image != null) {
                picture.Size = image.Size;
                InitPicturePosition();
                if (ImageChanged != null)
                    ImageChanged(this, EventArgs.Empty);
            }
        }
        private void InitPicturePosition() {
            if (image == null)
                return;
            picture.Location = new Point(
                (this.ClientSize.Width - image.Width) / 2,
                (this.ClientSize.Height - image.Height) / 2
            );
        }

        private void picture_MouseMove(object sender, MouseEventArgs e) {
            if (e.Button == System.Windows.Forms.MouseButtons.Left) {
                picture.Left += e.X - offsetX;
                picture.Top += e.Y - offsetY;
            }
        }
        private void picture_MouseDown(object sender, MouseEventArgs e) {
            if (e.Button == System.Windows.Forms.MouseButtons.Left) {
                offsetX = e.X;
                offsetY = e.Y;
            }
        }
        private void picture_MouseClick(object sender, MouseEventArgs e) {
            this.Focus();
            if (image != null && e.Button == System.Windows.Forms.MouseButtons.Middle) {
                picture.Size = image.Size;
                InitPicturePosition();
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e) {
            if (NativeMethods.IsKeyDown(NativeMethods.VK_CONTROL)) {
                int widthOffset = e.Delta / 4;
                int heightOffset = (e.Delta * picture.Height / 4 / picture.Width);
                if (picture.Width + widthOffset <= 0 || picture.Height + heightOffset <= 0)
                    return;
                picture.Width += widthOffset;
                picture.Height += heightOffset;
                picture.Left -= widthOffset / 2;
                picture.Top -= heightOffset / 2;
            } else {
                base.OnMouseWheel(e);
            }
        }
        protected override void OnDragEnter(DragEventArgs drgevent) {
            base.OnDragEnter(drgevent);
            if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
                drgevent.Effect = DragDropEffects.Copy;
        }
        protected override void OnDragDrop(DragEventArgs drgevent) {
            base.OnDragDrop(drgevent);
            string file = ((string[])drgevent.Data.GetData(DataFormats.FileDrop))[0];
            try {
                FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
                Image img = Image.FromStream(stream);
                byte[] bs;
                Guid fmt = img.RawFormat.Guid;
                if (fmt == ImageFormat.Jpeg.Guid)
                    bs = Encoding.ASCII.GetBytes("image/jpeg");
                else if (fmt == ImageFormat.Png.Guid)
                    bs = Encoding.ASCII.GetBytes("image/png");
                else {
                    stream.Close();
                    return;
                }
                byte[] buffer = new byte[(int)stream.Length + bs.Length + 4];
                int pos = 0;
                buffer[pos++] = 0;
                Array.Copy(bs, 0, buffer, pos, bs.Length);
                pos += bs.Length;
                buffer[pos++] = 0;
                buffer[pos++] = 0x03;
                buffer[pos++] = 0;
                int c;
                bs = new byte[1024];
                stream.Seek(0, SeekOrigin.Begin);
                while ((c = stream.Read(bs, 0, 1024)) > 0) {
                    Array.Copy(bs, 0, buffer, pos, c);
                    pos += c;
                }
                stream.Close();
                imageData = buffer;
                SetImage(img);
            } catch { }
        }
    }
}
